package org.easy.tool.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.easy.tool.common.HttpUtil;
import org.easy.tool.common.ListUtil;
import org.easy.tool.common.NumUtil;
import org.easy.tool.common.TimeUtil;
import org.easy.tool.entity.Company;
import org.easy.tool.entity.Constant;
import org.easy.tool.entity.Stock;
import org.easy.tool.mapper.StockMapper;
import org.easy.tool.service.ICompany;
import org.easy.tool.service.IStock;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Valley
 * @since 2024-02-27 21:58:59
 */
@Service
public class StockService extends ServiceImpl<StockMapper, Stock> implements IStock {

    public static final String BASE_URL = "http://api.waizaowang.com";
    public static final String TOKEN = "8cceb2ab595445e804622b6a9f63e824";
    public static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired
    ICompany companyService;

    /**
     * 功能：获取某个股票过去指定天数的数据
     */
    public List<Stock> getHistoryData(String code, int len) {
        List<Stock> stockList = new ArrayList<>();
        String date = TimeUtil.today();
        while (stockList.size() < len) {
            LambdaQueryWrapper<Stock> stockWrapper = new LambdaQueryWrapper<>();
            stockWrapper.eq(Stock::getCode, code).eq(Stock::getTdate, date);
            List<Stock> list = this.list(stockWrapper);
            stockList.addAll(list);
            date = TimeUtil.yesterday(date);
        }
        return stockList;
    }

    /**
     * 功能：获取最大值
     */
    public double getMaxValue(List<Stock> historyStock) {
        List<Object> collect = historyStock.stream().map(Stock::getZgj).collect(Collectors.toList());
        return NumUtil.save3Point((Double) NumUtil.min(collect));
    }

    /**
     * 功能：获取最小值
     */
    public Object getMinValue(List<Stock> historyStock) {
        List<Object> minCollect = historyStock.stream()
                .map(s -> {
                    Double jjia = (Double) s.getJjia();
                    Double zdj = (Double) s.getZdj();
                    return (jjia + zdj) / 2.0;
                })
                .collect(Collectors.toList());
        return NumUtil.save3Point((Double) NumUtil.min(minCollect));
    }

    /**
     * 功能：根据传递的code获取排序好的列表
     */
    public List<LinkedHashMap> getStockList(List<String> codeList) throws Exception {
        List<LinkedHashMap> priceList = new ArrayList<>();
        for (String code : codeList) {
            LinkedHashMap stock = getHistoryDayStock(code);
            priceList.add(stock);
        }
        return priceList.stream().sorted((a, b) -> {
            int aNum = (int) ((double) a.get("rate") * 1000);
            int bNum = (int) ((double) b.get("rate") * 1000);
            return (bNum - aNum);
        }).limit(10).collect(Collectors.toList());
    }


    /**
     * 功能：获取全部数据中排序好的列表
     */
    @Override
    public List<LinkedHashMap> getStockList() throws Exception {
        LambdaQueryWrapper<Company> companyWrapper = new LambdaQueryWrapper<>();
        long marketValue = 500 * 10000 * 10000L;
        companyWrapper.gt(Company::getMarketValue, marketValue).gt(Company::getRoe, 5.0);
        List<String> codeList = companyService.list(companyWrapper).stream()
                .map(Company::getCode).collect(Collectors.toList());
        return getStockList(codeList);
    }

    /**
     * 功能：获取股票实时数据
     */
    public Stock getStockNowData(String code) throws Exception {
        String url = BASE_URL + "/doc/getWatchStockTimeKLine" +
                "?code=" + code
                + "&type=1" +
                "&fields=all" +
                "&export=1" +
                "&token=" + TOKEN;
        String res = HttpUtil.get(url);
        LinkedHashMap map = MAPPER.readValue(res, LinkedHashMap.class);
        List<LinkedHashMap> data = (List<LinkedHashMap>) map.get("data");
        LinkedHashMap resMap = data.get(0);
        Stock stock = new Stock();
        stock.setName((String) resMap.get("name"));
        stock.setCode((String) resMap.get("code"));
        stock.setJjia(resMap.get("jjia"));
        return stock;
    }

    /**
     * 功能：根据code获取某只股票昨天的最新数据
     */
    public Stock getStockData(String code) throws Exception {
        String today = TimeUtil.today();
        LambdaQueryWrapper<Stock> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Stock::getCode, code).eq(Stock::getTdate, today);
        List<Stock> list = this.list(wrapper);
        if (list.size() == 0) {
            return getStockNowData(code);
        } else {
            return list.get(0);
        }
    }

    /**
     * 功能：跟据code获取历史90天的数据
     */
    public LinkedHashMap getHistoryDayStock(String code) throws Exception {
        LinkedHashMap map = new LinkedHashMap();
        LambdaQueryWrapper<Stock> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Stock::getCode, code);
        List<Stock> list = this.list(wrapper);
        List<Double> averageList = new ArrayList<>();
        for (Stock stock : list) {
            Double jjia = (Double) stock.getJjia();
            averageList.add(jjia);
        }
        Stock stockData = getStockData(code);
        Double yesterday = (Double) stockData.getJjia();
        int highNum = 0;
        for (Double everyDay : averageList) {
            if (everyDay > yesterday) {
                highNum += 1;
            }
        }
        Double roe = (Double) stockData.getRoe();
        Double ttmsyl = (Double) stockData.getTtmsyl();
        double rate = (highNum * 1.0 / averageList.size() * 0.5)
                + (roe / ttmsyl * 0.5);
        NumberFormat format = NumberFormat.getPercentInstance();
        format.setMaximumFractionDigits(2);
        String percentRate = format.format(rate);
        rate = NumUtil.save3Point(rate);
        map.put("A股编号", code);
        map.put("名称", stockData.getName());
        map.put("统计交易日", averageList.size());
        map.put("rate", rate);
        map.put("上涨概率", percentRate);
        List<Stock> historyData = getHistoryData(code, 5);
        String zgjList = historyData.stream()
                .map(Stock::getZgj)
                .map(s -> s + "")
                .collect(Collectors.joining("  "));
        String zdjList = historyData.stream()
                .map(Stock::getZdj)
                .map(s -> s + "")
                .collect(Collectors.joining("  "));
        String jJiaList = historyData.stream()
                .map(Stock::getJjia)
                .map(s -> s + "")
                .collect(Collectors.joining("  "));
        map.put("5日最高价", zgjList);
        map.put("5日平均价", jJiaList);
        map.put("5日最低价", zdjList);
        map.put("ROE", roe);
        map.put("市盈率TTM", ttmsyl);
        return map;
    }


    @Override
    public int refreshDateData(String startDate, String endDate) throws Exception {
        String url = BASE_URL + "/doc/getIndicatorBaseInfo?type=1" +
                "&startDate=" + startDate +
                "&endDate=" + endDate +
                "&fields=all" +
                "&export=1" +
                "&token=" + TOKEN;
        List<Company> list = companyService.list();
        List<Stock> stockList = new ArrayList<>();
        List<List<Company>> lists = ListUtil.splitList(list, 50);
        for (List<Company> companies : lists) {
            StringBuilder code = new StringBuilder();
            Company firstCompany = companies.get(0);
            code.append(firstCompany.getCode());
            for (int i = 1; i < companies.size(); i++) {
                code.append(",").append(companies.get(i).getCode());
            }
            String companyUrl = url + "&code=" + code.toString();
            String resData = HttpUtil.get(companyUrl);
            LinkedHashMap resMap = MAPPER.readValue(resData, LinkedHashMap.class);
            List<LinkedHashMap> dataList = (List<LinkedHashMap>) resMap.get("data");
            for (LinkedHashMap data : dataList) {
                Stock stock = new Stock();
                String companyCode = (String) data.get("code");
                stock.setCode(companyCode);
                String name = (String) data.get("name");
                stock.setName(name);
                String tdate = (String) data.get("tdate");
                stock.setTdate(tdate);
                Object price = data.get("price");
                stock.setPrice(price);
                Object hslv = data.get("hslv");
                stock.setHslv(hslv);
                Object dsyl = data.get("dsyl");
                stock.setDsyl(dsyl);
                Object cjl = data.get("cjl");
                stock.setCjl(cjl);
                Object cje = data.get("cje");
                stock.setCje(cje);
                Object zgj = data.get("zgj");
                stock.setZgj(zgj);
                Object zdj = data.get("zdj");
                stock.setZdj(zdj);
                Object jrkpj = data.get("jrkpj");
                stock.setJrkpj(jrkpj);
                Object zrspj = data.get("zrspj");
                stock.setZrspj(zrspj);
                Object zsz = data.get("zsz");
                stock.setZsz(zsz);
                Object sjlv = data.get("sjlv");
                stock.setSjlv(sjlv);
                String ssdate = (String) data.get("ssdate");
                stock.setSsdate(ssdate);
                Object roe = data.get("roe");
                stock.setRoe(roe);
                Object zys = data.get("zys");
                stock.setZys(zys);
                Object jlr = data.get("jlr");
                stock.setJlr(jlr);
                Object mlil = data.get("mlil");
                stock.setMlil(mlil);
                Object fzl = data.get("fzl");
                stock.setFzl(fzl);
                Object ttmsyl = data.get("ttmsyl");
                stock.setTtmsyl(ttmsyl);
                Object z71 = data.get("z71");
                stock.setZ71(z71);
                Object jzc = data.get("jzc");
                stock.setJzc(jzc);
                Object z79 = data.get("z79");
                stock.setZ79(z79);
                Object jjia = data.get("jjia");
                stock.setJjia(jjia);
                stockList.add(stock);
            }
        }
        this.saveBatch(stockList);
        return stockList.size();
    }

}
